package com.gitee.cui.netty.decoder;

import com.gitee.cui.util.RandomUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import org.junit.Test;

import java.nio.charset.StandardCharsets;

/**
 * 测试Netty中提供的开箱即用的解码器
 * @author cuiqingqiang
 * @version 1.0
 * @date 2021/10/25 9:08
 **/
public class NettyOpenBoxDecoderTest {

    private String spliter = "\r\n";

    private String content = "测试字符串";

    private String delimiter = "\r";

    private int version = 100;

    private int magicCode = 200;

    /**
     * 测试字符串行解码器，以换行符或者回车换行符结尾的字符串解码器
     */
    @Test
    public void lineBasedFrameDecoderTest() {
        ChannelInitializer<EmbeddedChannel> initializer = new ChannelInitializer<EmbeddedChannel>() {
            @Override
            protected void initChannel(EmbeddedChannel ch) throws Exception {
                ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
                ch.pipeline().addLast(new StringDecoder());
                ch.pipeline().addLast(new StringProcessHandler());
            }
        };

        EmbeddedChannel channel = new EmbeddedChannel(initializer);
        for (int i = 0; i < 100; i++) {
            int rand = RandomUtil.randInMod(3);
            ByteBuf buffer = Unpooled.buffer();
            for (int j = 0; j < rand; j++) {
                // 发送字符串内容
                buffer.writeBytes(content.getBytes(StandardCharsets.UTF_8));
            }
            // 发送结尾回车换行符作为结束符
            buffer.writeBytes(spliter.getBytes(StandardCharsets.UTF_8));
            channel.writeInbound(buffer);
        }

        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 测试自定义结束分隔符解码器
     */
    @Test
    public void delimiterBasedFrameDecoderTest() {
        ByteBuf buffer = Unpooled.buffer();
        buffer.writeBytes(delimiter.getBytes(StandardCharsets.UTF_8));
        ChannelInitializer<EmbeddedChannel> initializer = new ChannelInitializer<EmbeddedChannel>() {
            @Override
            protected void initChannel(EmbeddedChannel ch) throws Exception {
                ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, true, buffer));
                ch.pipeline().addLast(new StringDecoder());
                ch.pipeline().addLast(new StringProcessHandler());
            }
        };

        EmbeddedChannel channel = new EmbeddedChannel(initializer);
        for (int i = 0; i < 100; i++) {
            int rand = RandomUtil.randInMod(3);
            ByteBuf buf = Unpooled.buffer();
            for (int j = 0; j < rand; j++) {
                // 发送字符串内容
                buf.writeBytes(content.getBytes(StandardCharsets.UTF_8));
            }
            // 发送结尾回车换行符作为结束符
            buf.writeBytes(delimiter.getBytes(StandardCharsets.UTF_8));
            channel.writeInbound(buf);
        }

        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 测试长度字段数据包解码器
     */
    @Test
    public void lengthFieldBasedFrameDecoderTest() {
        LengthFieldBasedFrameDecoder lengthFieldBasedFrameDecoder = new LengthFieldBasedFrameDecoder(1024, 0, 4, 0, 4);
        ChannelInitializer<EmbeddedChannel> initializer = new ChannelInitializer<EmbeddedChannel>() {
            @Override
            protected void initChannel(EmbeddedChannel ch) throws Exception {
                ch.pipeline().addLast(lengthFieldBasedFrameDecoder);
                ch.pipeline().addLast(new StringDecoder());
                ch.pipeline().addLast(new StringProcessHandler());
            }
        };

        EmbeddedChannel channel = new EmbeddedChannel(initializer);
        for (int i = 0; i < 100; i++) {
            ByteBuf buf = Unpooled.buffer();
            String content = "第" + i + "次发送->" + this.content;
            byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
            buf.writeInt(bytes.length);
            // 发送字符串内容
            buf.writeBytes(content.getBytes(StandardCharsets.UTF_8));
            channel.writeInbound(buf);
        }

        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 测试长度字段数据包解码器，头部包含字符串长度（4字节）和版本号（2字节）
     */
    @Test
    public void lengthFieldBasedFrameDecoder2Test() {
        LengthFieldBasedFrameDecoder lengthFieldBasedFrameDecoder = new LengthFieldBasedFrameDecoder(1024, 0, 4, 2, 6);
        ChannelInitializer<EmbeddedChannel> initializer = new ChannelInitializer<EmbeddedChannel>() {
            @Override
            protected void initChannel(EmbeddedChannel ch) throws Exception {
                ch.pipeline().addLast(lengthFieldBasedFrameDecoder);
                ch.pipeline().addLast(new StringDecoder());
                ch.pipeline().addLast(new StringProcessHandler());
            }
        };

        EmbeddedChannel channel = new EmbeddedChannel(initializer);
        for (int i = 0; i < 100; i++) {
            ByteBuf buf = Unpooled.buffer();
            String content = "第" + i + "次发送->" + this.content;
            byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
            // 写入字符串长度
            buf.writeInt(bytes.length);
            // 写入字符串版本号
            buf.writeChar(version);
            // 发送字符串内容
            buf.writeBytes(content.getBytes(StandardCharsets.UTF_8));
            channel.writeInbound(buf);
        }

        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 测试长度字段数据包解码器，头部包含版本号(2字节)+字符串长度（4字节）+魔数（4字节）+字符串内容
     */
    @Test
    public void lengthFieldBasedFrameDecoder3Test() {
        LengthFieldBasedFrameDecoder lengthFieldBasedFrameDecoder = new LengthFieldBasedFrameDecoder(1024, 2, 4, 4, 10);
        ChannelInitializer<EmbeddedChannel> initializer = new ChannelInitializer<EmbeddedChannel>() {
            @Override
            protected void initChannel(EmbeddedChannel ch) throws Exception {
                ch.pipeline().addLast(lengthFieldBasedFrameDecoder);
                ch.pipeline().addLast(new StringDecoder());
                ch.pipeline().addLast(new StringProcessHandler());
            }
        };

        EmbeddedChannel channel = new EmbeddedChannel(initializer);
        for (int i = 0; i < 100; i++) {
            ByteBuf buf = Unpooled.buffer();
            String content = "第" + i + "次发送->" + this.content;
            byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
            // 写入字符串版本号
            buf.writeChar(version);
            // 写入字符串长度
            buf.writeInt(bytes.length);
            // 写入魔数
            buf.writeInt(magicCode);
            // 发送字符串内容
            buf.writeBytes(content.getBytes(StandardCharsets.UTF_8));
            channel.writeInbound(buf);
        }

        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
